﻿// =====================================================================
// <copyright file="ConfigManager.PCrypto.cs" author="David R. Guindo">
// 	Copyright (C) 2013. All rights reserved.
// </copyright>
// =====================================================================

namespace AppBlock.Config
{
    using System;
    using System.Configuration;
    using System.IO;

    public static partial class ConfigManager
    {
        private const string Configext = ".config";

        public static void EncryptSectionFiles(string sectionName, int parentLevel = 0, string environment = null)
        {
            EncryptDecryptInFiles(sectionName, true, parentLevel, environment);
        }

        public static void DecryptSectionFiles(string sectionName, int parentLevel = 0, string environment = null)
        {
            EncryptDecryptInFiles(sectionName, false, parentLevel, environment);
        }

        private static void EncryptDecryptInFiles(string sectionName, bool encrypt, int parentLevel, string environment)
        {
            if (environment == null) environment = Environment.MachineName;

            //Load Parent configuration
            if (parentLevel > 0)
            {
                string level = string.Empty;
                while (parentLevel > 0)
                {
                    level += "..\\";
                    string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, level, Configfilename);
                    if (File.Exists(path))
                    {
                        if (encrypt)
                            EncryptSection(sectionName, path);
                        else
                            DecryptSection(sectionName, path);
                    }
                    else
                    {
                        break;
                    }
                    parentLevel--;
                }
            }

            //Encrypt base configuration
            string exeConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                AppDomain.CurrentDomain.FriendlyName + Configext);
            if (File.Exists(exeConfigPath))
            {
                if (encrypt)
                    EncryptSection(sectionName, exeConfigPath);
                else
                    DecryptSection(sectionName, exeConfigPath);
            }

            if (string.IsNullOrWhiteSpace(environment)) return;

            //Encrypt Environment configuration
            string environmentFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config\\", environment,
                Configfilename);
            if (File.Exists(environmentFile))
            {
                if (encrypt)
                    EncryptSection(sectionName, environmentFile);
                else
                    DecryptSection(sectionName, environmentFile);
            }
        }


        /// <summary>
        ///     Decrypts the section.
        /// </summary>
        /// <param name="sectionName">Name of the section.</param>
        /// <param name="path">The path.</param>
        private static void DecryptSection(string sectionName, string path)
        {
            var configMap = new ExeConfigurationFileMap { ExeConfigFilename = path };

            var confg = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
            ConfigurationSection confStrSect = confg.GetSection(sectionName);
            if (confStrSect != null && confStrSect.SectionInformation.IsProtected)
            {
                confStrSect.SectionInformation.UnprotectSection();
                confStrSect.SectionInformation.ForceSave = true;
                confg.Save();
            }
        }

        /// <summary>
        /// Encrypts the section.
        /// </summary>
        /// <param name="sectionName">Name of the section.</param>
        /// <param name="path">The path.</param>
        private static void EncryptSection(string sectionName, string path)
        {
            try
            {
                var configMap = new ExeConfigurationFileMap { ExeConfigFilename = path };

                var confg = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
                ConfigurationSection confStrSect = confg.GetSection(sectionName);
                if (confStrSect != null && !confStrSect.SectionInformation.IsProtected)
                {
                    confStrSect.SectionInformation.ProtectSection(Provider);
                    confStrSect.SectionInformation.ForceSave = true;
                    confg.Save();
                }
            }
            catch (ConfigurationErrorsException)
            {
                //warning: if you don't have administrator privileges provider throw exception: object already exists.
                throw new Exception("Can't encrypt. Review if you have administrator privileges to do this.");
            }
        }
    }
}